package com.yingdong.sceneserver.opcode;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.yingdong.annotation.NoCheckPlayer;
import com.yingdong.sceneserver.inner.message.Message;
import com.yingdong.sceneserver.inner.message.RecvGameMessage;
import com.yingdong.sceneserver.net.GameUserSession;

import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;

public class Dispatcher {
	static Log logger = LogFactory.getLog(Dispatcher.class);
	public static Map<Integer, Method> methodMap = new HashMap<>();

	private static final int HANDLER_MAX_INDEX = 3000;
	// private static final int ERROR_MAX_ALLOW_COUNT = 100;
	private static final int TABLE_MAX_SIZE = 10000000;
	private static final int SESSION_CONNECTED = 2005;
	private static final int SESSION_CHECKS = 2006;
	public static BlockingQueue<ByteBuf> sendBuffers = new LinkedBlockingQueue<ByteBuf>(TABLE_MAX_SIZE);
	public static BlockingQueue<ByteBuf> receiveBuffers = new LinkedBlockingQueue<ByteBuf>(TABLE_MAX_SIZE);
	public static Channel sceneServerSession;
	public static final Map<Integer, GameUserSession> sessionMap = new ConcurrentHashMap<Integer, GameUserSession>();

	private static Thread recvThread;
	private static Dispatcher instance = null;

	private Dispatcher() {
		initHandlerTable();
		initThread();
	}

	public static Dispatcher getDispatcher() {
		if (instance == null) {
			instance = new Dispatcher();
		}
		return instance;
	}

	public static void init() {
		initHandlerTable();
		initThread();
	}

	public static void release() {
		recvThread.stop();
		recvThread = null;

		sceneServerSession.close();
		sceneServerSession = null;

		receiveBuffers.clear();
		receiveBuffers = null;

		sendBuffers.clear();
		sendBuffers = null;
	}

	private static void initHandlerTable() {

	}

	public static final void putSession(GameUserSession session) {
		sessionMap.put(session.getSessionId(), session);
	}

	public static final Set<Integer> getSessionMapKeySet() {
		return sessionMap.keySet();
	}

	public static final GameUserSession getSession(int sessionId) {
		return sessionMap.get(sessionId);
	}

	private static void initThread() {

		recvThread = new Thread(new Runnable() {

			GameUserSession session;
			ByteBuf buffer;

			@Override
			public void run() {
				while (true) {
					try {
						buffer = receiveBuffers.take();
						buffer.skipBytes(2);
						int sessionId = buffer.getInt(buffer.readShort());
						int opcode = buffer.readInt();
						String ip = null;
						if (opcode == SESSION_CONNECTED) {
							ip = Message.readString(buffer);
							putSession(new GameUserSession(sessionId, ip));
						} else if (opcode == SESSION_CHECKS) {
							Map<Integer, Integer> map = new HashMap<Integer, Integer>();
							for (int i = 0, size = buffer.readInt(); i < size; ++i) {
								int sid = buffer.readInt();
								map.put(sid, sid);
							}
							Set<Integer> set = getSessionMapKeySet();
							for (int tid : set) {
								if (!map.containsKey(tid)) {
									GameUserSession gameUserSession = getSession(tid);
									if (gameUserSession != null) {

									}
								}
							}
						} else if ((session = sessionMap.get(sessionId)) != null) {

							if (session.isHandle()) {

								Method method = methodMap.get(opcode);
								if (method != null) {
									if (method.getAnnotation(NoCheckPlayer.class) == null) {
										if (session.getObjectByKey("gamePlayer") == null) {
											logger.info("gamePlayer为空，请检查 opcode=" + opcode);
											continue;
										}
									}
									method.invoke(null, session, new RecvGameMessage(opcode, buffer));
								} else {
									logger.debug(opcode + "未注册处理方法");
								}
							}
						} else {
							putSession(new GameUserSession(sessionId, ip));
						}

					} catch (Exception e) {
						logger.error("", e);
					}
					finally {
						buffer.release();
					}

				}

			}
		});
		recvThread.start();

		// 消息发送线程
		Thread sendThread = new Thread(new Runnable() {

			@Override
			public void run() {
				while (true) {
					try {
						ByteBuf message = sendBuffers.take();
						// message.writeInt(message.getSessionId());
						sceneServerSession.writeAndFlush(message);
					} catch (Exception e) {
						logger.error("", e);
					}

				}

			}
		});
		// sendThread.start();

	}

}
